<?php
namespace WDB\Validation;
use WDB,
    WDB\Exception;

/**
 * Column validation rules collection.
 * 
 * Holds validation information for ColumnValidator for one column.
 * 
 * @author Richard Ejem <richard(at)ejem.cz>
 * @package WDB
 * 
 * @property-read int $type
 * @property-read string $message
 * @property-read mixed $argument
 */
class ColumnRules extends WDB\BaseCollection
{
    /** required field; cannot be empty string or NULL, depending on datatype */
    const REQUIRED = 1;
    
    /** value must be valid integer */
    const INTEGER = 2;
    
    /** value must be valid floating-point number*/
    const FLOAT = 3;
    
    /** string value must have a specified minimal character count*/
    const MINLENGTH = 4;
    
    /** string value must have a specified maximal character count*/
    const MAXLENGTH = 5;
    
    /** numeric value must be equal or greater than specified value*/
    const MINVALUE = 6;
    
    /** numeric value must be equal or lower than specified value*/
    const MAXVALUE = 7;
    
    /** string value must match specified regular expression (PCRE format) pattern*/
    const PATTERN = 8;
    
    /** value of the column must be equal to value of another column*/
    const EQUALTO = 9;
    
    /** string value must match built-in e-mail regular expression*/
    const EMAIL = -1;
    
    /** string value must match built-in url regular expression*/
    const URL = -2;
    
    /** value is validated by a specified callback function*/
    const CALLBACK = 10;
    
    /**@var string*/
    protected $columnTitle;
    
    public function __construct($columnTitle)
    {
        $this->columnTitle = $columnTitle;
    }
    
    /**
     * Sets minimal string length.
     *
     * @param int
     * @param string error message
     * @return ColumnRules fluent interface
     */
    public function minLength($value, $message = NULL)
    {
        return $this->set(WDB\Validation\ColumnRules::MINLENGTH, $message, 'minlength', $value);
    }
    
    /**
     * Sets maximal string length.
     *
     * @param int
     * @param string error message
     * @return ColumnRules fluent interface
     */
    public function maxLength($value, $message = NULL)
    {
        return $this->set(WDB\Validation\ColumnRules::MAXLENGTH, $message, 'maxlength', $value);
    }
    
    /**
     * Sets minimal numeric value
     *
     * @param int
     * @param string error message
     * @return ColumnRules fluent interface
     */
    public function minValue($value, $message = NULL)
    {
        return $this->set(WDB\Validation\ColumnRules::MINVALUE, $message, 'minvalue', $value);
    }
    
    /**
     * Sets maximal numeric value
     *
     * @param int
     * @param string error message
     * @return ColumnRules fluent interface
     */
    public function maxValue($value, $message = NULL)
    {
        return $this->set(WDB\Validation\ColumnRules::MAXVALUE, $message, 'maxvalue', $value);
    }
    
    /**
     * Sets that this field is required
     *
     * @param string error message
     * @return ColumnRules fluent interface
     */
    public function required($message = NULL)
    {
        return $this->set(WDB\Validation\ColumnRules::REQUIRED, $message, 'required', NULL);
    }
    
    /**
     * Sets that this field must be a valid integer
     *
     * @param string error message
     * @return ColumnRules fluent interface
     */
    public function integer($message = NULL)
    {
        return $this->set(WDB\Validation\ColumnRules::INTEGER, $message, 'integer', NULL);
    }
    
    /**
     * Sets that this field must be a valid float number
     *
     * @param string error message
     * @return ColumnRules fluent interface
     */
    public function float($message = NULL)
    {
        return $this->set(WDB\Validation\ColumnRules::FLOAT, $message, 'float', NULL);
    }
    
    /**
     * Sets that this field must be equal to another column's field
     *
     * @param string column name to compare
     * @param string error message
     * @return ColumnRules fluent interface
     */
    public function equals($columnName, $message = NULL)
    {
        return $this->set(WDB\Validation\ColumnRules::EQUALTO, $message, 'equals', $columnName);
    }
    
    /**
     * Sets a callback which will validate this field
     *
     * @param callback
     * @param string error message
     * @return ColumnRules fluent interface
     */
    public function callback($callback, $message = NULL)
    {
        if (!$rule['argument'] instanceof \WDB\Utils\Caller && !is_callable($rule['argument']))
        {
            throw new Exception\BadArgument("Validation rule with custom callback need the callback to be an instance of \WDB\Utils\Caller");
        }
        return $this->set(WDB\Validation\ColumnRules::CALLBACK, $message, 'callback', $callback);
    }
    
    /**
     * Sets a pcre pattern this field will be validated by.
     *
     * @param string pcre regular expression pattern
     * @param string error message
     * @return ColumnRules fluent interface
     */
    public function pattern($pcre_regex, $message = NULL)
    {
        return $this->set(WDB\Validation\ColumnRules::PATTERN, $message, 'pattern', $pcre_regex);
    }
    
    /**
     * Sets that this field must be a valid e-mail address.
     *
     * @param string error message
     * @return ColumnRules fluent interface
     */
    public function email($message = NULL)
    {
        return $this->set(WDB\Validation\ColumnRules::EMAIL, $message, 'email', NULL);
    }
    
    /**
     * Sets that this field must be a valid URL.
     *
     * @param string error message
     * @return ColumnRules fluent interface
     */
    public function url($message = NULL)
    {
        return $this->set(WDB\Validation\ColumnRules::URL, $message, 'url', NULL);
    }
    
    /**
     * Sets that this field is not required (can be empty or NULL)
     *
     * @param string error message
     * @return ColumnRules fluent interface
     */
    public function notRequired()
    {
        $this->remove(WDB\Validation\ColumnRules::REQUIRED);
    }
    
    /**
     * Resets that this field don't have to be integer
     *
     * @param string error message
     * @return ColumnRules fluent interface
     */
    public function noInteger()
    {
        $this->remove(WDB\Validation\ColumnRules::INTEGER);
    }
    
    /**
     * Resets that this field don't have to be float
     *
     * @param string error message
     * @return ColumnRules fluent interface
     */
    public function noFloat()
    {
        $this->remove(WDB\Validation\ColumnRules::FLOAT);
    }
    
    /**
     * Resets this field's minimal string length
     *
     * @param string error message
     * @return ColumnRules fluent interface
     */
    public function noMinLength()
    {
        $this->remove(WDB\Validation\ColumnRules::MINLENGTH);
    }
    
    /**
     * Resets this field's maximal string length
     *
     * @param string error message
     * @return ColumnRules fluent interface
     */
    public function noMaxLength()
    {
        $this->remove(WDB\Validation\ColumnRules::MAXLENGTH);
    }
    
    /**
     * Resets this field's minimal numeric value
     *
     * @param string error message
     * @return ColumnRules fluent interface
     */
    public function noMinValue()
    {
        $this->remove(WDB\Validation\ColumnRules::MINVALUE);
    }
    
    /**
     * Resets this field's maximal numeric value
     *
     * @param string error message
     * @return ColumnRules fluent interface
     */
    public function noMaxValue()
    {
        $this->remove(WDB\Validation\ColumnRules::MAXVALUE);
    }
    
    /**
     * Resets this field's pcre validator
     *
     * @param string error message
     * @return ColumnRules fluent interface
     */
    public function noPattern()
    {
        $this->remove(WDB\Validation\ColumnRules::PATTERN);
    }
    
    /**
     * Resets this field's callback validator
     *
     * @param string error message
     * @return ColumnRules fluent interface
     */
    public function noCallback()
    {
        $this->remove(WDB\Validation\ColumnRules::CALLBACK);
    }
    
    /**
     *
     * @param int $type rule constant Rule::* or instantiated Rule class
     * @param string $message error message on violated rule
     * @param string $defaultMessage language identifier of string representing default error message
     *  in lang namespace validator.messages
     * @param mixed $argument rule argument (max length etc)
     * @return self
     */
    protected function set($type, $message, $defaultMessage, $argument)
    {
        if ($type < 0)
        {
            switch ($type)
            {
                case -1:
                    $type = 8;
                    $argument = '~^.*@.*\\..*~';
                    break;
                case -2:
                    $type = 8;
                    $argument = '~^([a-z][a-z0-9.+-]*)?://(.*@)?[a-z0-9-]+~';
                    break;
            }
        }
        if ($message === NULL)
        {
            $message = WDB\Lang::s('validator.messages.'.$defaultMessage);
        }
        $this[$type] = array('message'=>$this->parseMessage($message, $argument), 'argument'=>$argument);
        return $this;
    }
    
    
    protected function parseMessage($msg, $argument)
    {
        return str_replace(array('%name', '%arg'),
                array($this->columnTitle, $argument),
                $msg);
    }
    
    protected function remove($type)
    {
        unset($this[$type]);
        return $this;
    }
}